package com.bsj.sipgateway.sip.event.online;

import com.alibaba.fastjson.JSON;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.def.dto.DeviceRegisterMidDTO;
import com.bsj.power.common.def.dto.RedisDeviceInfo;
import com.bsj.power.common.def.entity.gb28181.Device;
import com.bsj.power.common.def.entity.gb28181.DeviceChannel;
import com.bsj.power.common.mapper.DeviceChannelMapper;
import com.bsj.sipgateway.util.RedisDeviceInfoUtil;
import com.bsj.sipgateway.cache.DeviceCache;
import com.bsj.sipgateway.common.constant.Constants;
import com.bsj.sipgateway.sip.bean.Position;
import com.bsj.sipgateway.sip.session.PositionManager;
import com.bsj.sipgateway.sip.transmit.cmd.impl.SIPCommander;
import com.bsj.sipgateway.web.service.IDeviceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import redis.clients.bsj.JedisClusterBSJ;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author bsj-chenjunkang
 * @Description: 在线事件监听器，监听到离线后，修改设备离在线状态。 设备在线有两个来源：
 * 1、设备主动注销，发送注销指令，{@link com.bsj.sipgateway.sip.transmit.request.impl.RegisterRequestProcessor}
 * 2、设备未知原因离线，心跳超时,{@link com.bsj.sipgateway.sip.transmit.request.impl.MessageRequestProcessor}
 * @date 2022/8/31
 */
@Slf4j
@Component
public class OnlineEventListener implements ApplicationListener<OnlineEvent> {

    @Autowired
    @Qualifier("deviceServiceImpl")
    private IDeviceService deviceService;

    @Autowired
    private SIPCommander cmder;

    @Autowired
    private RedisDeviceInfoUtil redisDeviceInfoUtil;

    @Autowired
    private JedisClusterBSJ jedisClusterBSJ;

    @Autowired
    private DeviceChannelMapper deviceChannelMapper;

    @Override
    public void onApplicationEvent(OnlineEvent event) {
        log.debug("设备上线事件触发，deviceId：" + event.getDevice().getDeviceId() + ",from:" + event.getFrom());
        try {
            // 获取redis中设备的缓存信息
            RedisDeviceInfo redisDeviceInfo = null;
            long nowTime = System.currentTimeMillis();
            switch (event.getFrom()) {
                case Constants.EVENT_ONLINE_REGISTER:
//                    ResetChannelCache.setResetFlag(event.getDevice().getDeviceId(), ResetChannelCache.needResetFlag);
                    Device deviceDB = deviceService.selectByDeviceId(event.getDevice().getDeviceId());
                    if (deviceDB == null) {
                        log.info("数据库没有该设备，不处理注册信息，deviceId={}", event.getDevice().getDeviceId());
                        return;
                    }
                    Long did = deviceDB.getId();
                    Device device = event.getDevice();
                    device.setId(did);
                    device.setDeviceId(deviceDB.getDeviceId());
                    device.setName(deviceDB.getName());
                    device.setNickName(deviceDB.getNickName());
                    device.setChannelIdStr(deviceDB.getChannelIdStr());
                    device.setChannelNumber(deviceDB.getChannelNumber());
                    device.setManufacturer(deviceDB.getManufacturer());
                    device.setModel(deviceDB.getModel());
                    device.setFirmware(deviceDB.getFirmware());
                    device.setPathId(deviceDB.getPathId());
                    device.setSceneId(deviceDB.getSceneId());

                    // 设置设备的通道信息
                    List<DeviceChannel> deviceChannels = deviceChannelMapper.queryAllChannels(event.getDevice().getDeviceId());
                    if (!CollectionUtils.isEmpty(deviceChannels)) {
                        Map<String, DeviceChannel> deviceChannelMap = new HashMap<>();
                        for (DeviceChannel deviceChannel : deviceChannels) {
                            deviceChannelMap.put(deviceChannel.getChannelId(), deviceChannel);
                        }
                        device.setDeviceChannelMap(deviceChannelMap);
                    }

                    DeviceCache.putDevice(device);
                    // 更新数据库的ip
                    deviceService.updateIpAndPortByDeviceId(device);
                    log.info("设备注册上线，修改数据库设备的IP信息，ip={},port={},hostAddress={},deviceId={}"
                            , device.getIp(), device.getPort(), device.getHostAddress(), device.getDeviceId());

                    redisDeviceInfo = redisDeviceInfoUtil.getRedisDeviceInfo(event.getDevice().getDeviceId());
                    if (redisDeviceInfo == null) {
                        setRedisDeviceInfo(device);
                    } else {
                        redisDeviceInfo.setRegisterTime(nowTime);
                        redisDeviceInfo.setOnline(Constants.DEVICE_ONLINE);
                        redisDeviceInfo.setKeepAliveTime(nowTime);
                        redisDeviceInfo.setDeviceAbnormalOffline(0);
                        redisDeviceInfoUtil.setRedisDeviceInfo(redisDeviceInfo);
                    }

                    // 校验并写入device的注册注销中间状态
                    checkAndSetDeviceRegisterMidDTO(device);

                    break;
                // 设备主动发送心跳触发的在线事件
                case Constants.EVENT_ONLINE_KEEPLIVE:
                    // 更新缓存设备在线状态
                    DeviceCache.putDevice(event.getDevice());
                    Position position = event.getPosition();
                    if (position != null) {
                        PositionManager.put(event.getDevice().getDeviceId(), position);
                    } else {
                        position = PositionManager.get(event.getDevice().getDeviceId());
                        if (position != null) {
                        } else {
//                            cmder.catalogQuery(event.getDevice());
                        }
                    }
                    // 更新redis中的di数据
                    redisDeviceInfo = redisDeviceInfoUtil.getRedisDeviceInfo(event.getDevice().getDeviceId());
                    if (redisDeviceInfo != null) {
                        redisDeviceInfo.setKeepAliveTime(nowTime);
                        redisDeviceInfoUtil.setRedisDeviceInfo(redisDeviceInfo);
                    } else {
                        Device device1 = deviceService.selectByDeviceId(event.getDevice().getDeviceId());
                        if (device1 != null) {
                            setRedisDeviceInfo(device1);
                        }
                    }

                    break;
            }
        } catch (Exception e) {
            log.error("处理在线事件异常", e);
        }
    }


    /**
     * 存入redis缓存
     */
    private void setRedisDeviceInfo(Device device) {
        if (device == null) {
            return;
        }
        RedisDeviceInfo rdi = new RedisDeviceInfo();
        rdi.setId(device.getId());
        rdi.setDeviceId(device.getDeviceId());
        rdi.setOnline(Constants.DEVICE_ONLINE);
        long now = System.currentTimeMillis();
        rdi.setKeepAliveTime(now);
        rdi.setRegisterTime(now);
        rdi.setChannelNumber(device.getChannelNumber());
        rdi.setChannelIdStr(device.getChannelIdStr());
        rdi.setLogoutTime(null);
        rdi.setSceneId(device.getSceneId());
        rdi.setDeviceAbnormalOffline(0);
        redisDeviceInfoUtil.setRedisDeviceInfo(rdi);
    }

    /**
     * 校验并写入device的注册注销中间状态
     *
     * @param device
     */
    private void checkAndSetDeviceRegisterMidDTO(Device device) {
        if (device == null) {
            return;
        }
        Long did = device.getId();
        String deviceId = device.getDeviceId();
        long nowTime = System.currentTimeMillis();
        // 先获取
        String hget = jedisClusterBSJ.hget(RedisConstant.DEVICE_REGISTER_MID_DTO, did + "");
        DeviceRegisterMidDTO midDTO = null;
        if (hget == null || "".equals(hget)) {
            // 第一次默认是没有的，就写入一个
            midDTO = new DeviceRegisterMidDTO();
            midDTO.setDid(did);
            midDTO.setDeviceId(deviceId);
        } else {
            midDTO = JSON.parseObject(hget, DeviceRegisterMidDTO.class);
        }
        midDTO.setRegisterTime(nowTime);
        jedisClusterBSJ.hset(RedisConstant.DEVICE_REGISTER_MID_DTO, did + "", JSON.toJSONString(midDTO));

    }

}
